予焦啦!歡迎各位讀者點進這個系列文!
第一天,我們不囉唆直接去拉取 Hoddarla
專案吧!
筆者建議讀者跟隨快速上手章節的部份就好,應該可以直接跑出一個具備計時器中斷(timer interrupt)功能的小型展示。這個展示包含的內容大約涵蓋到第 20 天的內容,後續還在趕工中。現在的這個名為
debut
的分支,將目前為止的 Hoddarla 開發進度壓成了一整個 patch。之後隨著每一天的推進,筆者會依序揭露試誤與開發的過程。
git clone git@github.com:NonerKao/Hoddarla.git && cd Hoddarla
make env
. .hdlarc
make
理論上,應該可以看到
...
i = 16
i = 15
i = 14
i = 13
i = 12
i = 11
i = 10
i = 9
i = 8
i = 7
i = 6
i = 5
i = 4
i = 3
i = 2
i = 1
i = 16
i = 15
i = 14
i = 13
i = 12
i = 11
的一連串倒數。是的,這就是囉!
以下是 make env
較細部的拆解,但實務上應該是沒有必要的,只是參照用。
考量到 RISC-V 硬體還不是很好取得,開發者總還是必須要有一個可運行系統的平台才行,所以通常就使用功能最齊全的模擬器 QEMU。
筆者使用 QEMU 6.1.0 的版本。以下將幾個套件取消掉並非絕對,只是現階段還不需要那些功能罷了。--target-list
則是必要的,因為 QEMU 能夠支援多種平台與架構,這裡指定的 riscv64-softmmu
通常用以運行 Linux。prefix
雖非必要但仍然強烈建議,因為如此一來,就可以很方便的管理安裝目錄了。
./configure \
--target-list=riscv64-softmmu \
--disable-sdl \
--disable-vnc \
--disable-gtk \
--prefix=$HOME/qemu
# 可自行調整想安裝的目錄位址,建議將 $HOME/qemu/bin 也加入 PATH 環境變數
如果成功的話,會顯示一整排的組態,以及它們是否被啟動或取消。這之後就可以
make && make install
目前 Hoddarla 還是需要仰賴 GNU 的 C 工具鏈。自己編的話需要花一點時間,如果可以使用發行版就有的軟體包,也是可以考慮的選項。
最簡單的方法就是先拉取一份 riscv-gnu-toolchain 到自己的開發環境,然後開始建置
git clone https://github.com/riscv/riscv-gnu-toolchain
cd riscv-gnu-toolchain
git submodule update --init riscv-gcc
git submodule update --init riscv-newlib
git submodule update --init riscv-binutils
git submodule update --init riscv-gdb
mkdir build && cd build && ../configure --prefix=$HOME/toolchain
make
結束之後就會產生預設 64-bit 的 newlib 工具鏈。
筆者沒有使用過這些版本。若要使用這類型的工具鏈於 Hoddarla 實驗或開發的話可能會因此需要一些調整。
Select arch
選擇 riscv64,glibc 和 musl 應該都可以使用。community/riscv64-elf-binutils
與 community/riscv64-elf-gdb
:可以直接使用 pacman -S
安裝筆者在 2016年底首次參加ITHOME的鐵人賽。
該次系列文是非常淺碟的學習筆記,內容也沒有什麼特殊之處,是關於使用者空間與Linux作業系統核心之間的系統呼叫介面。那次的經驗讓我明顯感受到,鐵人賽本質上是一場猶如馬拉松的盛會;參賽者們位在其中,各自由意志力驅使自我成長,同時也有機會學習他人或供他人學習,整個活動空間於是成為多面向且多維度的集體學習場域。
撰寫系列文是很有趣,介紹性質或是學習性質的文章也可以幫助初學者,但是要更加提升的話,必定要往更深處走去吧。
於是在後來的兩年,2018 與第 11 屆 2020,筆者決定鎖定更具體的範圍、訂出明確的目標。前者是以 binutils 這樣偉大的專案為目標去試圖實作一部分子集合,後者則是追蹤 Golang 內建的各種機制。以結果來說,兩篇系列文最後還是流於通泛了,但它們確實標註了筆者過去幾年以來一直都很感興趣的的技術主軸:RISC-V 以及 Golang 。
這一次,筆者決定開始一個以 Golang 與 RISC-V 兩個主題為雙軸線的作業系統專案,並將之命名為 Hoddarla。當然,要是說我打算在這 30 天內一天累積一點點的速度,完成一個作業系統,那未免也太瞧不起數十年來累積的作業系統原理與技術了。
事實上,在第十一屆(上上屆)鐵人賽結束之後,筆者就已經著手進行 Hoddarla 專案:使用 Golang 打造一個 RISC-V 的作業系統。到今年(寫作的此時,是 2021)初期累積了非常微小的一點點成果,遠遠不及當初的恢宏夢想,但還是以這次鐵人賽為契機紀錄一下;題目也相對應的修改成符合事實的描述:Hoddarla 專案起步:使用 Golang 撰寫 RISC-V 作業系統的初步探索。
以下數個小節,就解析這個題目的若干名詞對筆者的意義之所在。希望在今天這一篇開宗明義的文章當中能夠指引各位讀者,通往後續幾篇技術文章的道路或許會更有趣一些。
這兩個大項目純粹是筆者的興趣,也因此想要做的題目形式上會成為兩者的交集點,事實上兩者沒有什麼關聯。RISC-V 是眾所矚目的第五代簡化指令集架構,官方單位(RISC-V 國際基金會)以電腦系統的巴別塔為己任,以模組化的彈性為最大的賣點,技術社群與規格社群也相當蓬勃地發展當中。Golang 則是一個高階的靜態編譯程式語言,語法簡潔卻功能強大,由頗負盛名的Ken Thompson(Unix之父、C語言之父)、Rob Pike(UTF-8編碼設計者)以及Robert Griesemer開發。
若真的要定位出兩者的相同點,也不是沒有:
或許還可以再補上一則筆者的個人主觀意見,那就是兩者都還沒有得到應有的地位。試想一個內建擴充性的計算機指令集架構(ISA),如果能夠讓全世界共享其中的基礎部分,能夠相消弭多少的額外負擔?又,一個語法極簡卻提供垃圾回收、輕量程序與內建並行機制的語言,可以為多少軟體工程師節省認知負荷?然而世界並非如此運作,這兩者能夠在歷史之中挺立多久,都尚屬未知。
至於兩者真正的交集,也就是 Golang 內的 RISC-V 架構支援,目前只有 Linux 作業系統堪稱較完整,但其實也還非常初階。僅有 64-bit 的支援不說,能夠大幅節省編譯產物空間的壓縮指令集(C extension)也還沒有支援。
若是各位讀者對於 Golang 與 RISC-V 之間的真正的交集有興趣,筆者曾提交兩個功能實作,都已經進入到 Golang 的歷史之中。相關主題會在最後倒數幾日時的附錄主題與各位分享。
無論如何,由於我完全認同這兩者背後的哲學,但又沒有非常充裕的時間能夠徹底研究這兩者,所以才會繼前兩組鐵人系列文之後,再於今年度的鐵人賽延續這個雙軸線。
我們可以從不同角度檢視一個程式語言:語法、語意如何處理、執行時環境(runtime)與行為,都有各自的學問與鑽研的趣味。
在這裡我特別想比較的是工具鏈(toolchain)的部份。C 語言工具鏈的編譯牽涉到多個軟體元件、多個專案的偕同工作才有辦法達成。若要簡單的描述 GNU C 工具鏈的編譯流程的話,那麼得先將鏈結器、組譯器之類的工具編譯出來,再以這些工具先編譯出一個功能有限的 C 編譯器;然後再用這個編譯器去編譯 C 函式庫,這時候才能讓 gcc 專案使用到 C 函式庫的功能並編譯成一個整體。Golang 的話,若非特殊情況,相依性管理完全不是問題,因為它自己為自己實作了編譯器,也就是所謂的自主(Self-Hosting)。
工具鏈本身編好之後,若要執行測試來檢驗它是否功能正常,C 語言需要外部的測試專案;但是,go 語言已將單元測試當作是語言的基本功能,也能夠在編譯好工具鏈之後自動執行所有標準函式庫的測試。
執行時間則是另外一個兩者相差懸殊的項目,我在同一台電腦上面實測的結果,C 語言工具鏈的下載與編譯時間都大概是 Golang 的 9 倍左右。
從使用者的角度來看的話,我覺得最大的一個差異在於交叉編譯(cross-compilation)的支援。C 語言部分,以 GNU 工具鏈為例的話,交叉編譯往往仰賴建置工具 autotool
系列所提供的功能;誠然,相關資訊在網路上都非常容易取得,也容易理解。但有些 C 語言為主的專案,它預設使用的建置系統並無 GNU 建置工具整合,那麼要交叉編譯就有可能要費一番手腳;又,就算有整合 GNU 建置工具,若是要支援新平台,專案本身和 GNU 建置工具裡面的部分設定檔可能都需要更新,這需要不特定且無法輕易估算的額外工夫。
各位讀者知道什麼叫做 Cannadian Build 嗎?這是在描述一種很有趣的交叉編譯需求。你最強力的運算機器是架構 A,但你預期會用到交叉編譯工具鏈的機器是架構 B,而這隻交叉編譯工具所能夠處理與生成的產物是屬於架構 C。我實測在 x86_64 上為 ARM64 編譯 RISC-V 需要的工具鏈,結果是寸步難行:最一開始,GNU 工具會提示你,這個編譯工作會需要 x86_64 到 ARM64 的交叉工具鏈,這就算了;就算你備有了,他接下來還會跟你要 ARM64 上面所需要的各種過程中的相依函式庫。
反觀 Golang,交叉編譯功能是內建的。Golang 專案需要的建置指令只是 go build
,所以如果想要為 ARM 64 位元處理器上的 FreeBSD 系統建置這個專案,只需要多給兩個環境變數
GOOS=freebsd GOARCH=arm64 go build
旋即搞定。筆者甚至沒有辦法花更多篇幅來說明它,這個抽象層切得妙到顛毫,所有無須深入理解的細節全部都被隱藏。
由此,我們不難發現,Golang 作為一個語言,的確解決了一些困擾著前人的問題,而它解決那些問題的解法也確實的成為這個語言本身提供的工具。
本節舉這個工具鏈交叉編譯的例子,對於 Hoddarla 專案本身不是太具意義,因為我們已經限定 RISC-V 64-bit 了。也許圍繞在 Golang 上面更合適介紹的主題是
go mod
導入的內建相依性管理,但就留待日後有機會再行研究。
Jserv 在八卦版的一篇文 曾引述王祐中博士的一句話:「寫一個作業系統是多麼美好的事,在有限的生命中千萬不要遺漏了它。」無獨有偶,這次鐵人賽也由另外一位參賽鐵人 EN 也引用了這句話在他打算要打造的 RISC-V 作業系統的系列文介紹當中。
若以人類的文明活動作為類比,作業系統負責的項目應該可以類比於政府體系、官僚制度或者是任何非現代政府形式的調解手段。原因是,作業系統負責管控資源,能夠監控它們的狀態且有最終決定權,然後接收使用者的需求並將這些資源分配給他們。這麼說來,將寫一個作業系統視作美好之事,大概略可以類比於那些想要設計社會制度的思想家,或是有才幹能夠在有限規則中將政府的運作調理得宜的政治家吧。
然而在電腦系統中,寫一個專案就意味著作者有著至高權限,比之皇帝或是史上任何的獨裁者都還具有更多的發揮空間,簡直就是神一般的存在。這麼一想,的確是令人嚮往的事情。
但如果只是不論結果的撰寫而已,感覺又略嫌缺乏。雖然人們常說意義在過程不在結果,但通常那要嘛是安慰人的話語,要嘛是結果不重要或是難以估量。筆者謙卑的希望 Hoddarla 能夠至少在過程的意義之外還能夠具備一些其他的意義,但也如同前述的那樣,今年能夠完成的部份實在是頂多只有初期的一部分,就算要高談闊論些精神層面的事情,也不是現在吧。
Hoddarla 背後的想法很單純。筆者最一開始煩惱了很久,到底該將這個專案命名為什麼才能夠彰顯那種無須多言的簡單感覺,幸好傳統語言的智慧自然在對的時刻浮現腦海。
Golang 的執行期環境(runtime)提供了非常豐富的功能,包含排程、Goroutine(Golang 的 coroutine)、還有垃圾回收機制。單這樣描述,就已經很像是作業系統核心的部份內容了,不是嗎?當然,一個現代的作業系統核心包含了很多很多很多其他的功能,但從無到有不就是這麼回事嗎?那我們何不試試用 Golang 來寫作業系統呢?
需要特別注意的是,這裡面有個應當釐清的誤區。上一段的聯想實際上代表著,也許 Golang 的執行期環境能夠代替某些作業系統核心的功能,但這和用 Golang 寫作業系統的意義不盡相同,值得細分。
以 C 語言為例,用 C 語言寫 Linux 沒有什麼難以想像的,畢竟是已屆 30 年的實踐。然而,Linux 並不使用 C 語言的執行期環境。Linux 需要 bootloader 幫它處理載入時的核心參數,而不是像一般 C 語言專案那樣,由 C 語言的執行期處理參數,再以 int main(int argc, char *argv[])
的方便形式傳遞。所以從 C 的例子就能夠明確看出兩者的差異。
那麼,Hoddarla 專案所冀求的又是哪一種呢?筆者認為在這個階段(這次鐵人賽所包含的範圍內),是只能涵蓋前者的一部分。至於用 Golang 寫作業系統,在附錄的部份會有一些文獻回顧,介紹前人的嘗試,並較深入一點地研究目前最完整的一個使用 Golang 撰寫的作業系統核心;關鍵字是 biscuit。
因此,現階段 Hoddarla 的絕大部分程式碼都依附在 Golang 專案之中;甚至我們可以說,Hoddarla 目前還只是 Golang 的 RISC-V 執行期的一個小 patchset 而已。筆者在裡面發展現有 RISC-V 工具鏈不足之處,增補執行期所需,然後在執行期環境的啟動過程中一個一個加入作業系統應有的功能。
作為 patchset,筆者的例行公事就是每隔一段時間就要將既有的部份 rebase 到上游的 Golang 上面。Hoddarla 啟動至今已經這樣操作十數次,大部份是執行期環境的 API 改動,偶爾涉及到物件處理的部份而需要重新編譯工具鏈。繁瑣的細節在附錄中也將補述。
晶心壯士團體第一次上台領獎時,記得主辦單位提供了隊長發表感言的時段。當時筆者秉持著感動與感謝,將這場盛會與馬拉松做聯想,以強調其中的耐力成份。現在鐵人賽規模更顯壯大了,除了自我的耐力考驗之外,如果還獨學而無友,顯然白白糟蹋了一場祭典。所以筆者這裡也列出相關主題,以示重點關注:
當然最後也一定要介紹一下敝組晶心壯士中的另外兩位鐵人。他們都是是筆者在晶心科技的同事。他們帶來的兩個系列將分別是
予焦啦!感謝各位讀者願意在這裡見證 Hoddarla 專案的起步。我們明天再會!